﻿using Kimd.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace Kimd.Motion
{
    [Serializable]
    public class Cylinder : ICsv
    {
        [XmlIgnore]
        public short _bitNo1 { get; private set; }
        private short _bitNo2 = -1;
        private Dictionary<int, int> cardNo2Count;
        private ControlCard _card1;
        [XmlIgnore]
        public ControlCard Card1
        {
            get { return _card1; }
            set { _card1 = value; }

        }
        private ControlCard _card2;
        [XmlIgnore]
        public ControlCard Card2
        {
            get { return _card2; }
            set { _card2 = value; }
        }
        public string Description { get; set; }
        public string Module { get; set; }
        public string ControlCardName1 { get; set; }
        public string ControlCardName2 { get; set; }
        private string _id1;
        public string ID1
        {
            get
            {
                return _id1;
            }
            set
            {
                _id1 = value;
                if (cardNo2Count != null && !string.IsNullOrEmpty(_id1))
                {
                    int index = 0;
                    int cardCount = 0;
                    foreach (var item in cardNo2Count)
                    {
                        if (item.Key.Equals(Convert.ToInt32(_id1.Split('_')[0])))
                        {
                            index += Convert.ToInt32(_id1.Split('_')[2].Substring(3));
                            break;
                        }
                        else
                        {
                            index += item.Value;
                        }
                        cardCount++;
                    }
                    _bitNo1 = (short)index;
                }
            }
        }
        private string _id2;
        public string ID2
        {
            get
            {
                return _id2;
            }
            set
            {
                _id2 = value;
                if (cardNo2Count != null && !string.IsNullOrEmpty(_id2))
                {
                    if (cardNo2Count != null)
                    {
                        int index = 0;
                        int cardCount = 0;
                        foreach (var item in cardNo2Count)
                        {
                            if (item.Key.Equals(Convert.ToInt32(_id2.Split('_')[0])))
                            {
                                index += Convert.ToInt32(_id2.Split('_')[2].Substring(3));
                                break;
                            }
                            else
                            {
                                index += item.Value;
                            }
                            cardCount++;
                        }
                        _bitNo2 = (short)index;
                    }
                }
            }
        }
        private List<Sensor> _moves;
        [XmlIgnore]
        public List<Sensor> Moves
        {
            get { return _moves; }
            set
            {
                _moves = value;
                if (this._moves != null)
                {
                    if (MoveNames == null)
                        MoveNames = new List<string>();
                    foreach (Sensor s in this._moves)
                    {
                        MoveNames.Add(s.Description);
                    }
                }
            }
        }
        private List<Sensor> _origins;
        [XmlIgnore]
        public List<Sensor> Origins
        {
            get { return _origins; }
            set
            {
                _origins = value;
                if (this._origins != null)
                {
                    if (OriginNames == null)
                        OriginNames = new List<string>();
                    foreach (Sensor s in this._origins)
                    {
                        OriginNames.Add(s.Description);
                    }
                }
            }
        }
        public List<string> MoveNames { get; set; }
        public List<string> OriginNames { get; set; }
        public SerializableDictionary<string, string> CsvName2Property { get; set; }
        [XmlIgnore]
        public Func<(bool,string)> PreCheckOn { get; set; }
        [XmlIgnore]
        public Func<(bool, string)> PreCheckOff { get; set; }

        [XmlIgnore]
        public List<string> CardConfig
        {
            set
            {
                cardNo2Count = new Dictionary<int, int>();
                if (value != null)
                {
                    int index = 0;
                    foreach (var item in value)
                    {
                        if (item.Split('_')[1].Equals("DO8") ||
                            item.Split('_')[1].Equals("DO16") ||
                            item.Split('_')[1].Equals("DO32"))
                        {
                            cardNo2Count.Add(Convert.ToInt32(item.Split('_')[0]), Convert.ToInt32(item.Split('_')[1].Substring(2)));
                            index++;
                        }
                        if (item.Split('_')[1].Equals("DIO8") ||
                            item.Split('_')[1].Equals("DIO16") ||
                            item.Split('_')[1].Equals("DIO32"))
                        {
                            cardNo2Count.Add(Convert.ToInt32(item.Split('_')[0]), Convert.ToInt32(item.Split('_')[1].Substring(3)));
                            index++;
                        }
                    }
                    ID1 = _id1;
                    ID2 = _id2;
                }
            }
        }
        public Cylinder()
        {
            MoveNames = new List<string>();
            OriginNames = new List<string>();
            Moves = new List<Sensor>();
            Origins = new List<Sensor>();
            CsvName2Property = new SerializableDictionary<string, string>();
            CsvName2Property.Add("名称", nameof(Description));
            CsvName2Property.Add("所属模组", nameof(Module));
            CsvName2Property.Add("所属轴卡1", nameof(ControlCardName1));
            CsvName2Property.Add("ID1", nameof(ID1));
            CsvName2Property.Add("所属轴卡2", nameof(ControlCardName2));
            CsvName2Property.Add("ID2", nameof(ID2));
        }
        public Cylinder(string name)
            : this()
        {
            this.Description = name;
        }
        public Cylinder(string name, string cardName1, string id1, string moduleName, string cardName2 = "", string id2 = "",
                        List<Sensor> move = null, List<Sensor> origin = null)
            : this(name)
        {
            this.ControlCardName1 = cardName1;
            this.ID1 = id1;
            this.ControlCardName2 = cardName2;
            this.ID2 = id2;
            this.Moves = move;
            this.Origins = origin;
            this.Module = moduleName;
            if (this.Moves != null)
            {
                if (MoveNames == null)
                    MoveNames = new List<string>();
                foreach (Sensor s in this.Moves)
                {
                    MoveNames.Add(s.Description);
                }
            }
            if (this.Origins != null)
            {
                if (OriginNames == null)
                    OriginNames = new List<string>();
                foreach (Sensor s in this.Origins)
                {
                    OriginNames.Add(s.Description);
                }
            }
        }
        public (bool,string) On()
        {
            bool result = true;
            string errInfo = "";
            if (PreCheckOn != null)
                (result,errInfo) = PreCheckOn.Invoke();
            if (result)
            {
                if (_bitNo2 != -1)
                {
                    _card2.DigitalOperator.ClearOutBitStatus(Card2.CardNo, _bitNo2);
                    _card1.DigitalOperator.SetOutBitStatus(Card1.CardNo, _bitNo1);
                }
                else
                    _card1.DigitalOperator.SetOutBitStatus(Card1.CardNo, _bitNo1);
            }
            return (result, errInfo);
        }
        public (bool, string) Off()
        {
            bool result = true;
            string errInfo = "";
            if (PreCheckOff != null)
                (result, errInfo) = PreCheckOff.Invoke();
            if (result)
            {
                if (_bitNo2 != -1)
                {
                    _card2.DigitalOperator.SetOutBitStatus(Card2.CardNo, _bitNo2);
                    _card1.DigitalOperator.ClearOutBitStatus(Card1.CardNo, _bitNo1);
                }
                else
                    _card1.DigitalOperator.ClearOutBitStatus(Card1.CardNo, _bitNo1);
            }
            return (result, errInfo);
        }
        public bool AlreadyOn()
        {
            if (_card1 == null)
                return false;
            if (_bitNo2 != -1)
                return _card1.DigitalOperator.GetOutBitStatus(Card1.CardNo, _bitNo1) && !_card2.DigitalOperator.GetOutBitStatus(Card2.CardNo, _bitNo2);
            return _card1.DigitalOperator.GetOutBitStatus(Card1.CardNo, _bitNo1);
        }
        public bool AlreadyOff()
        {
            if (_bitNo2 != -1)
                return !_card1.DigitalOperator.GetOutBitStatus(Card1.CardNo, _bitNo1) && _card2.DigitalOperator.GetOutBitStatus(Card2.CardNo, _bitNo2);
            return !_card1.DigitalOperator.GetOutBitStatus(Card1.CardNo, _bitNo1);
        }
        public bool WaitOn(int waitTime = 0)
        {
            bool result = true;
            string errInfo = "";
            if (PreCheckOn != null)
                (result, errInfo) = PreCheckOn.Invoke();
            if (result)
                On();
            else
                return false;
            return InMove(waitTime);
        }
        public bool WaitOff(int waitTime = 0)
        {
            bool result = true;
            string errInfo = "";
            if (PreCheckOff != null)
                (result, errInfo) = PreCheckOff.Invoke();
            if (result)
                Off();
            else
                return false;
            return InOrigin(waitTime);
        }
        public bool InMove(int waitTime = 0)
        {
            if (Moves != null)
            {
                bool isInMove = true;
                foreach (Sensor move in Moves)
                {
                    isInMove = move.WaitOn(waitTime) && isInMove;
                    if (!isInMove)
                        break;
                }
                return isInMove;
            }
            else
            {
                if (Origins != null)
                {
                    bool isInMove = true;
                    foreach (Sensor origin in Origins)
                    {
                        isInMove = !origin.WaitOn(waitTime) && isInMove;
                        if (!isInMove)
                            break;
                    }
                    return isInMove;
                }
                else
                    return true;
            }
        }
        public bool InOrigin(int waitTime = 0)
        {
            if (Origins != null)
            {
                bool isInOrigin = true;
                foreach (Sensor origin in Origins)
                {
                    isInOrigin = origin.WaitOn(waitTime) && isInOrigin;
                    if (!isInOrigin)
                        break;
                }
                return isInOrigin;
            }
            else
            {
                if (Moves != null)
                {
                    bool isInOrigin = true;
                    foreach (Sensor move in Moves)
                    {
                        isInOrigin = !move.WaitOn(waitTime) && isInOrigin;
                        if (!isInOrigin)
                            break;
                    }
                    return isInOrigin;
                }
                else
                    return true;
            }
        }
        public void Stop()
        {
            //双控气缸，停止
            if (_bitNo2 != -1)
            {
                _card2.DigitalOperator.ClearOutBitStatus(Card2.CardNo, _bitNo2);
                _card1.DigitalOperator.ClearOutBitStatus(Card1.CardNo, _bitNo1);
            }
        }
    }
}
